// src/pages/StockAminuteChart/StockAminuteChart.jsx

import React, { useEffect, useRef, useState } from 'react';
import * as echarts from 'echarts';
import {
  Card,
  Input,
  Select,
  Spin,
  message,
  Checkbox,
  Row,
  Col,
  Typography
} from 'antd';
import { $fetchAStockMinute } from '../../api/stockApi';
import './StockAminuteChart.scss';

const { Search } = Input;
const { Option } = Select;
const { Title, Text } = Typography;

// 可选技术指标
const INDICATORS = [
  { label: 'MA (5,10,20)', value: 'MA' },
  { label: 'MACD', value: 'MACD' },
  { label: 'RSI', value: 'RSI' },
  { label: 'KDJ', value: 'KDJ' },
  { label: 'BOLL', value: 'BOLL' }
];

const AMinuteChart = () => {
  const chartRef = useRef(null);
  const chartInstance = useRef(null);

  const [symbol, setSymbol] = useState('sh900901');
  const [period, setPeriod] = useState('1');
  const [loading, setLoading] = useState(false);
  const [minuteData, setMinuteData] = useState([]);
  const [indicators, setIndicators] = useState([]);

  // ─────────────────────────────────────────────────────────────
  // 工具：把字符串数组转数字（NaN→0）
  const toNumberArr = (arr) =>
    arr.map((v) => {
      const num = parseFloat(v);
      return isNaN(num) ? 0 : num;
    });

  // MA 均线
  const calcMA = (arr, n) => {
    const res = [];
    for (let i = 0; i < arr.length; i++) {
      if (i < n - 1) {
        res.push(null);
      } else {
        let sum = 0;
        for (let j = i - n + 1; j <= i; j++) sum += arr[j];
        res.push(parseFloat((sum / n).toFixed(4)));
      }
    }
    return res;
  };

  // EMA 指数均线
  const calcEMA = (arr, n) => {
    const res = [];
    const alpha = 2 / (n + 1);
    let prev = null;
    arr.forEach((v, i) => {
      const price = v != null ? v : 0;
      if (i === 0) {
        prev = price;
        res.push(parseFloat(price.toFixed(4)));
      } else {
        const ema = alpha * price + (1 - alpha) * prev;
        res.push(parseFloat(ema.toFixed(4)));
        prev = ema;
      }
    });
    return res;
  };

  // MACD
  const calcMACD = (closeArr) => {
    const ema12 = calcEMA(closeArr, 12);
    const ema26 = calcEMA(closeArr, 26);
    const DIF = ema12.map((v, i) =>
      v != null && ema26[i] != null ? parseFloat((v - ema26[i]).toFixed(4)) : null
    );
    const dea = calcEMA(DIF.map((v) => (v == null ? 0 : v)), 9).map((v) =>
      parseFloat(v.toFixed(4))
    );
    const MACD = DIF.map((v, i) =>
      v == null || dea[i] == null ? null : parseFloat((2 * (v - dea[i])).toFixed(4))
    );
    return { DIF, DEA: dea, MACD };
  };

  // RSI
  const calcRSI = (closeArr, n = 14) => {
    const res = [];
    let gains = 0,
      losses = 0;
    for (let i = 1; i < closeArr.length; i++) {
      const change = closeArr[i] - closeArr[i - 1];
      gains += Math.max(change, 0);
      losses += Math.max(-change, 0);
      if (i < n) {
        res.push(null);
      } else if (i === n) {
        const rg = gains / n;
        const rl = losses / n;
        res.push(parseFloat((rl === 0 ? 100 : 100 - 100 / (1 + rg / rl)).toFixed(2)));
      } else {
        const change2 = closeArr[i] - closeArr[i - 1];
        gains = gains - gains / n + Math.max(change2, 0);
        losses = losses - losses / n + Math.max(-change2, 0);
        const rg = gains / n;
        const rl = losses / n;
        res.push(parseFloat((rl === 0 ? 100 : 100 - 100 / (1 + rg / rl)).toFixed(2)));
      }
    }
    res.unshift(null);
    return res;
  };

  // KDJ
  const calcKDJ = (h, l, c, n = 9) => {
    const len = c.length;
    const K = [],
      D = [],
      J = [];
    let prevK = 50,
      prevD = 50;
    for (let i = 0; i < len; i++) {
      if (i < n - 1) {
        K.push(null);
        D.push(null);
        J.push(null);
      } else {
        const high = Math.max(...h.slice(i - (n - 1), i + 1));
        const low = Math.min(...l.slice(i - (n - 1), i + 1));
        const rsv = high === low ? 50 : ((c[i] - low) / (high - low)) * 100;
        const currK = (2 / 3) * prevK + (1 / 3) * rsv;
        const currD = (2 / 3) * prevD + (1 / 3) * currK;
        K.push(parseFloat(currK.toFixed(2)));
        D.push(parseFloat(currD.toFixed(2)));
        J.push(parseFloat((3 * currK - 2 * currD).toFixed(2)));
        prevK = currK;
        prevD = currD;
      }
    }
    return { K, D, J };
  };

  // BOLL
  const calcBOLL = (c, n = 20, k = 2) => {
    const MB = [],
      UB = [],
      LB = [];
    for (let i = 0; i < c.length; i++) {
      if (i < n - 1) {
        MB.push(null);
        UB.push(null);
        LB.push(null);
      } else {
        const slice = c.slice(i - (n - 1), i + 1);
        const ma = slice.reduce((a, b) => a + b, 0) / n;
        const sd = Math.sqrt(
          slice.reduce((acc, v) => acc + (v - ma) ** 2, 0) / n
        );
        MB.push(parseFloat(ma.toFixed(4)));
        UB.push(parseFloat((ma + k * sd).toFixed(4)));
        LB.push(parseFloat((ma - k * sd).toFixed(4)));
      }
    }
    return { MB, UB, LB };
  };

  // ─────────────────────────────────────────────────────────────
  // Step1: 拉取并存储分钟线
  useEffect(() => {
    const chart = echarts.init(chartRef.current);
    chartInstance.current = chart;

    const load = async () => {
      if (!symbol) return;
      setLoading(true);
      chart.showLoading();
      try {
        const data = await $fetchAStockMinute({ symbol, period });
        if (!Array.isArray(data) || !data.length) {
          throw new Error('数据为空');
        }
        setMinuteData(data);
      } catch (err) {
        console.error(err);
        message.error('获取数据失败，请检查代码或网络');
      } finally {
        chart.hideLoading();
        setLoading(false);
      }
    };

    load();
    window.addEventListener('resize', () => chart.resize());
    return () => {
      window.removeEventListener('resize', () => chart.resize());
      chart.dispose();
      chartInstance.current = null;
    };
  }, [symbol, period]);

  // ─────────────────────────────────────────────────────────────
  // Step2: 数据 & 指标变化时重绘
  useEffect(() => {
    const chart = chartInstance.current;
    if (!chart || !minuteData.length) return;

    // 2.1 解构
    const times = minuteData.map((d) => d.time);
    const opens = toNumberArr(minuteData.map((d) => d.open));
    const highs = toNumberArr(minuteData.map((d) => d.high));
    const lows = toNumberArr(minuteData.map((d) => d.low));
    const closes = toNumberArr(minuteData.map((d) => d.close));
    const volumes = toNumberArr(minuteData.map((d) => d.volume));

    // 2.2 各指标
    const ma5 = calcMA(closes, 5);
    const ma10 = calcMA(closes, 10);
    const ma20 = calcMA(closes, 20);
    const { DIF, DEA, MACD } = calcMACD(closes);
    const rsiArr = calcRSI(closes, 14);
    const { K: kArr, D: dArr, J: jArr } = calcKDJ(highs, lows, closes, 9);
    const { MB, UB, LB } = calcBOLL(closes, 20, 2);

    // 2.3 构造 option（原逻辑完全保留，不赘述）
    const grids = [];
    const xAxes = [];
    const yAxes = [];
    const series = [];

    // —— 主区：价格 + MA/BOLL + 成交量
    const top0 = '5%';
    const height0 =
      indicators.includes('MACD') ||
      indicators.includes('RSI') ||
      indicators.includes('KDJ')
        ? '25%'
        : '75%';
    grids.push({ top: top0, height: height0, left: '8%', right: '5%' });
    yAxes.push({
      gridIndex: 0,
      name: '价格',
      position: 'left',
      scale: true,
      splitLine: { show: false },
      axisLabel: { color: '#999' }
    });
    xAxes.push({
      gridIndex: 0,
      type: 'category',
      data: times,
      boundaryGap: false,
      axisLabel: {
        show:
          !(
            indicators.includes('MACD') ||
            indicators.includes('RSI') ||
            indicators.includes('KDJ')
          )
      },
      axisLine: { lineStyle: { color: '#888' } },
      axisTick: { show: false },
      splitLine: { show: false }
    });
    series.push({
      name: '价格',
      type: 'line',
      data: closes,
      xAxisIndex: 0,
      yAxisIndex: 0,
      smooth: true,
      lineStyle: { width: 1, color: '#5470C6' },
      showSymbol: false
    });
    if (indicators.includes('MA')) {
      series.push(
        {
          name: 'MA5',
          type: 'line',
          data: ma5,
          xAxisIndex: 0,
          yAxisIndex: 0,
          lineStyle: { width: 1, opacity: 0.6, color: '#EE6666' },
          showSymbol: false
        },
        {
          name: 'MA10',
          type: 'line',
          data: ma10,
          xAxisIndex: 0,
          yAxisIndex: 0,
          lineStyle: { width: 1, opacity: 0.6, color: '#91CC75' },
          showSymbol: false
        },
        {
          name: 'MA20',
          type: 'line',
          data: ma20,
          xAxisIndex: 0,
          yAxisIndex: 0,
          lineStyle: { width: 1, opacity: 0.6, color: '#FAC858' },
          showSymbol: false
        }
      );
    }
    if (indicators.includes('BOLL')) {
      series.push(
        {
          name: 'BOLL_MB',
          type: 'line',
          data: MB,
          xAxisIndex: 0,
          yAxisIndex: 0,
          lineStyle: { width: 1, color: '#AAAAAA', opacity: 0.7 },
          showSymbol: false
        },
        {
          name: 'BOLL_UB',
          type: 'line',
          data: UB,
          xAxisIndex: 0,
          yAxisIndex: 0,
          lineStyle: { width: 1, color: '#888888', opacity: 0.7 },
          showSymbol: false
        },
        {
          name: 'BOLL_LB',
          type: 'line',
          data: LB,
          xAxisIndex: 0,
          yAxisIndex: 0,
          lineStyle: { width: 1, color: '#888888', opacity: 0.7 },
          showSymbol: false
        }
      );
    }
    series.push({
      name: '成交量',
      type: 'bar',
      data: volumes,
      xAxisIndex: 0,
      yAxisIndex: 0,
      barWidth: '60%',
      itemStyle: { color: '#B0BEC5', opacity: 0.5 },
      z: -1
    });

    // —— MACD
    if (indicators.includes('MACD')) {
      const top1 = '35%';
      const height1 =
        indicators.includes('RSI') || indicators.includes('KDJ') ? '15%' : '35%';
      grids.push({ top: top1, height: height1, left: '8%', right: '5%' });
      yAxes.push({
        gridIndex: grids.length - 1,
        name: 'MACD',
        position: 'left',
        scale: true,
        splitLine: { show: false },
        axisLabel: { color: '#999' }
      });
      xAxes.push({
        gridIndex: grids.length - 1,
        type: 'category',
        data: times,
        boundaryGap: true,
        axisLabel: {
          show:
            indicators.includes('KDJ') || indicators.includes('RSI') ? false : true
        },
        axisLine: { lineStyle: { color: '#888' } },
        axisTick: { show: false },
        splitLine: { show: false }
      });
      series.push(
        {
          name: 'DIF',
          type: 'line',
          data: DIF,
          xAxisIndex: grids.length - 1,
          yAxisIndex: grids.length - 1,
          lineStyle: { width: 1, color: '#EE6666' },
          showSymbol: false
        },
        {
          name: 'DEA',
          type: 'line',
          data: DEA,
          xAxisIndex: grids.length - 1,
          yAxisIndex: grids.length - 1,
          lineStyle: { width: 1, color: '#5470C6' },
          showSymbol: false
        },
        {
          name: 'MACD_Hist',
          type: 'bar',
          data: MACD.map((v) => (v == null ? 0 : v)),
          xAxisIndex: grids.length - 1,
          yAxisIndex: grids.length - 1,
          itemStyle: {
            color: (p) => (p.value >= 0 ? '#26A69A' : '#EF5350')
          }
        }
      );
    }

    // —— RSI
    if (indicators.includes('RSI')) {
      const top2 = indicators.includes('MACD')
        ? indicators.includes('KDJ')
          ? '55%'
          : '50%'
        : '35%';
      const height2 = indicators.includes('KDJ') ? '15%' : '35%';
      grids.push({ top: top2, height: height2, left: '8%', right: '5%' });
      yAxes.push({
        gridIndex: grids.length - 1,
        name: 'RSI(14)',
        position: 'left',
        scale: true,
        splitLine: { show: false },
        axisLabel: { color: '#999' }
      });
      xAxes.push({
        gridIndex: grids.length - 1,
        type: 'category',
        data: times,
        boundaryGap: false,
        axisLabel: { show: indicators.includes('KDJ') ? false : true },
        axisLine: { lineStyle: { color: '#888' } },
        axisTick: { show: false },
        splitLine: { show: false }
      });
      series.push({
        name: 'RSI',
        type: 'line',
        data: rsiArr,
        xAxisIndex: grids.length - 1,
        yAxisIndex: grids.length - 1,
        lineStyle: { width: 1, color: '#FF9800' },
        showSymbol: false
      });
    }

    // —— KDJ
    if (indicators.includes('KDJ')) {
      const top3 = '75%';
      grids.push({ top: top3, height: '20%', left: '8%', right: '5%' });
      yAxes.push({
        gridIndex: grids.length - 1,
        name: 'KDJ',
        position: 'left',
        scale: true,
        splitLine: { show: false },
        axisLabel: { color: '#999' }
      });
      xAxes.push({
        gridIndex: grids.length - 1,
        type: 'category',
        data: times,
        boundaryGap: false,
        axisLabel: { show: true },
        axisLine: { lineStyle: { color: '#888' } },
        axisTick: { show: false },
        splitLine: { show: false }
      });
      series.push(
        {
          name: 'K',
          type: 'line',
          data: kArr,
          xAxisIndex: grids.length - 1,
          yAxisIndex: grids.length - 1,
          lineStyle: { width: 1, color: '#FFEB3B' },
          showSymbol: false
        },
        {
          name: 'D',
          type: 'line',
          data: dArr,
          xAxisIndex: grids.length - 1,
          yAxisIndex: grids.length - 1,
          lineStyle: { width: 1, color: '#03A9F4' },
          showSymbol: false
        },
        {
          name: 'J',
          type: 'line',
          data: jArr,
          xAxisIndex: grids.length - 1,
          yAxisIndex: grids.length - 1,
          lineStyle: { width: 1, color: '#E91E63' },
          showSymbol: false
        }
      );
    }

    // 最后同步 dataZoom
    const dataZoom = [
      {
        type: 'inside',
        xAxisIndex: grids.map((_, i) => i),
        start: 0,
        end: 100
      },
      {
        show: true,
        type: 'slider',
        xAxisIndex: grids.map((_, i) => i),
        bottom: 0,
        start: 0,
        end: 100
      }
    ];

    const option = {
      tooltip: {
        trigger: 'axis',
        axisPointer: { type: 'cross' },
        confine: true,
        axisPointer: {
          label: { backgroundColor: '#333', color: '#fff', padding: [4,7] }
        }
      },
      legend: {
        top: '2%',
        left: 'center',
        data: series.map((s) => s.name),
        textStyle: { fontSize: 12 }
      },
      grid: grids,
      xAxis: xAxes,
      yAxis: yAxes,
      dataZoom,
      series
    };

    chart.setOption(option, true);
    chart.resize();
  }, [minuteData, indicators]);

  return (
    <div className="a-minute-chart-page">
      <Card className="a-minute-chart-card" bordered={false}>
        {/* 标题 */}
        <div className="chart-header">
          <Title level={3}>A 股/指数 分时图 + 技术指标</Title>
          <Text type="secondary">实时分钟线 + 多种常用指标</Text>
        </div>
        {/* 控件 */}
        <div className="chart-controls">
          <Row gutter={16} align="middle">
            <Col>
              <Search
                placeholder="输入股票代码"
                allowClear
                enterButton="搜 索"
                onSearch={(v) => {
                  if (!v.trim()) {
                    message.warning('请输入股票代码');
                    return;
                  }
                  setSymbol(v.trim());
                }}
                className="control-item"
                style={{ width: 200 }}
              />
            </Col>
            <Col>
              <Select
                value={period}
                onChange={setPeriod}
                className="control-item"
                style={{ width: 100 }}
              >
                <Option value="1">1 分钟</Option>
                <Option value="5">5 分钟</Option>
                <Option value="15">15 分钟</Option>
                <Option value="30">30 分钟</Option>
                <Option value="60">60 分钟</Option>
              </Select>
            </Col>
            <Col flex="auto">
              <Checkbox.Group
                options={INDICATORS}
                value={indicators}
                onChange={setIndicators}
                className="control-item"
              />
            </Col>
          </Row>
        </div>
        {/* 图表 */}
        <Spin spinning={loading} tip="加载分钟线..." className="spin-center">
          <div ref={chartRef} className="chart-container" />
        </Spin>
      </Card>
    </div>
  );
};

export default AMinuteChart;
